package au.edu.unsw.editingtool.web;

/**
 * @author r.chen
 * 
 * Login Manager handle all login matters.
 * 
 */

import java.io.IOException;
import java.sql.SQLException;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import au.edu.unsw.editingtool.authentication.LDAP;
import au.edu.unsw.editingtool.db.DBAffiliation;
import au.edu.unsw.editingtool.db.DBGroup;
import au.edu.unsw.editingtool.db.DBUser;
import au.edu.unsw.editingtool.db.DBClaim;
import au.edu.unsw.editingtool.db.DBLogin;
import au.edu.unsw.editingtool.db.DBSession;
import au.edu.unsw.editingtool.db.DBPublication;
import au.edu.unsw.editingtool.global.EditingToolException;
import au.edu.unsw.editingtool.global.GlobalConstant;
import au.edu.unsw.editingtool.global.PropertyReader;


/**
 * Servlet implementation class LoginManager
 * Just check the login of the user on the LDAP.
 * Then set the session and user information on the db.
 */
public class LoginManager extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private String ServletContext = "";
	private String ApplicationPath = null;
	
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public LoginManager() {
        super();
        // TODO Auto-generated constructor stub        
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		this.doService(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		this.doService(request, response);
	}
	
	protected void doService(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
	{
		ServletContext = getServletContext().getRealPath("") + GlobalConstant.fileSeparator;		
		ApplicationPath = request.getContextPath();	
		System.out.println("==== [LOGINMANAGER Servlet] ====");
		
		HttpSession session = request.getSession();
		
		// Get username and password from header.
		String username = request.getParameter(GlobalConstant.username);
		String password = request.getParameter(GlobalConstant.password);
		String sessionid = session.getId();
		String querystring = request.getQueryString();
		if (querystring == null)
			querystring ="";
		
		System.out.println("[LOGINMANAGER] Querystring : "+querystring);
		
		Boolean login = false;
				
		// Get the configuration.
		PropertyReader configReader = null;
		try {			
			configReader = new PropertyReader();
			configReader.setFile(ServletContext + GlobalConstant.configFilePath);			
			configReader.buildConfiguration();			
		}
		catch (Exception ex)
		{
			// TODO better Auto-generated catch block
			ex.printStackTrace();
		}

		// LDAP login
		// This setting depends in the configuration
		if(configReader.getConfigValue(new String[]{GlobalConstant.LDAP,"authentication"})=="true")
		{
			System.out.println("[LOGINMANAGER] LDAP Authentication");
			LDAP ldap = new LDAP();
			ldap.setPropertyFile(ServletContext + GlobalConstant.configFilePath);
			System.out.println("[LOGINMANAGER] LDAP configfile : "+ServletContext + GlobalConstant.configFilePath);
			Hashtable<String, String> ldapresult = this.getLDAPAuthenticatedAtributes(ldap);
			if(ldapresult!=null)
			{					
				Enumeration<String> ldapkeys = ldapresult.keys();
				while (ldapkeys.hasMoreElements())
				{
					String key = ldapkeys.nextElement();
					String value = ldapresult.get(key);
					session.setAttribute(key,value);						
				}
				session.setAttribute("ldap_result","LDAP DATA");
			}
			else
			{
				session.setAttribute("ldap_result","LDAP EMPTY");
			}		
			boolean valid = this.getLDAPAuthenticated(ldap, username, password);
		
			if (valid)		
			{
				login=true;
				
				//Update or add user info to DB Login table
			} 			
		}
		
		// Check login from DB Login table
		if(!login)
		{
			login=this.authenticate(username, password);
		}
		
		// After DB Login authentication. check the result. If false forward back to login
		if(!login)
		{			
			System.out.println("[LOGINMANAGER] Login is FALSE");			
			request.setAttribute(GlobalConstant.responseType,GlobalConstant.typeError);
			request.setAttribute(GlobalConstant.responseControl, GlobalConstant.cmdLogin);
			request.setAttribute(GlobalConstant.responseMsg, "Authentication Error! Please relogin!");
			
			System.out.println("[LOGINMANAGER] Forward to "+GlobalConstant.JSPLogin);
			RequestDispatcher rd = request.getRequestDispatcher(GlobalConstant.JSPLogin+"?"+querystring);
			rd.forward(request, response);			
			return;
		}		
		
		// DB Session
		// After the login is success update the session in session table.
		// Put java session id on the session table and sid from session table to java session.
		
		String userGroup = this.getGroup(username);
		DBSession dbsession = new DBSession();
		dbsession.setConfFile(ServletContext + GlobalConstant.configFilePath);
		Long newdate = (Long) session.getLastAccessedTime();
		Integer timeout = (Integer) session.getMaxInactiveInterval(); 
		//System.out.println("[LOGINMANAGER] date : "+newdate);		
		String sid = null;
		try 
		{
			sid=dbsession.addSession(sessionid, username, newdate.toString(), timeout.toString(), "1");						
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		String redirectUrl = GlobalConstant.ServletMain+"?";
		if(request.getParameter(GlobalConstant.pid) != null)
		{
			if(request.getParameter(GlobalConstant.requestCommand) != null)
			{
				if(request.getParameter(GlobalConstant.requestCommand).toString().compareTo(GlobalConstant.cmdEdit)==0)
					redirectUrl = GlobalConstant.ServletEdit+"?";
			}
		}			
		System.out.println("[LOGINMANAGER] SID = "+sid);
		System.out.println("[LOGINMANAGER] Redirect to MAIN Servlet");			
					
		session.setAttribute(GlobalConstant.username,username);
		session.setAttribute(GlobalConstant.userGroup,userGroup);
		session.setAttribute(GlobalConstant.sid,sid);
		session.setAttribute(GlobalConstant.requestLastCommand,GlobalConstant.cmdLogin);						
		response.sendRedirect(redirectUrl+querystring);
	}
	
	private boolean getLDAPAuthenticated(LDAP ldap, String username, String password) {
		
		if ((username == null) || (username.trim().length() < 0))
			return false;
		if ((password == null) || (password.trim().length() < 0))
			return false;	
		
		return ldap.authenticate(username, password);
	}
	
	private Hashtable<String, String> getLDAPAuthenticatedAtributes(LDAP ldap) {
		if(ldap.isValid())
		{
			if(!ldap.isAttributesEmpty())
			{
				Hashtable<String, String> attributes = (Hashtable<String, String>)ldap.getAttributes();
				return attributes;
			}
			else
			{
				Hashtable<String, String> attributes = new Hashtable<String, String>();
				attributes.put("RESULT","EMPTY");	
			}
		}
		Hashtable<String, String> attributes = new Hashtable<String, String>();
		attributes.put("RESULT","NULL");
		return attributes;
	}
	private boolean authenticate(String username, String password)
	{
		boolean result = false;
		boolean isUsername= false;
		
		if(username==null || username.length()==0 || password==null || password.length()==0)
			return result;
		
		DBLogin dblogin = new DBLogin();
		dblogin.setConfFile(ServletContext + GlobalConstant.configFilePath);
		try {
			isUsername = dblogin.loginExists(username);
		} 
		catch (Exception e) {			
			e.printStackTrace();
		}
		//System.out.println("[LOGINMANAGER] isUsername : "+isUsername);
		
		if (!isUsername)
			return result;
		else
		{	try
			{
				result = dblogin.authenticate(username, password);
			}
			catch (Exception ex)
			{
				ex.printStackTrace();
			}
		}
		return result;		
	}
	
	private String getGroup(String username)
	{
		String groupid = null;
		String group=null;
		
		if(username==null || username.length()==0)
			return group;
		
		try
		{
			DBLogin dblogin = new DBLogin();
			dblogin.setConfFile(ServletContext + GlobalConstant.configFilePath);
			groupid = dblogin.getGroup(username);
			
			System.out.println("[LOGINMANAGER] Group ID : "+groupid);
			DBGroup dbgroup = new DBGroup();
			dbgroup.setConfFile(ServletContext + GlobalConstant.configFilePath);
			//System.out.println("GroupID : "+dbgroup.MappingTable.get("GroupID"));
			group=dbgroup.getGroupName(groupid);
			
			System.out.println("[LOGINMANAGER] Group Name : "+group);
		}
		catch (Exception Ex)
		{
			Ex.printStackTrace();
		}
				
		return group;		
	}
}
